Codeforces 451E. Devu and Flowers(容斥)

题意:

$求x_1+x_2+…+x_n\le s, x_1\le f1, x_2\le f_2,…,x_n\le f_n的方法数,答案模10^9 + 7$
$n\le 20, f_i\le 10^{12}, s\le 10^{14}$

分析:

$容斥原理套路题,令事件A_i:=至少x_i>f_i的解的方法数$
$显然ans=$
$所以容斥一波就好了,计算每个的时候,先把超过的部分减掉,剩下的就转化成了$
$left个物品装进n个盒子,盒子可以为空的问题,这个用隔板法就可以了$
$大组合数取模用lucas,组合数由于1个很小,直接暴力就可以了$

$代码:$

//
//  Created by TaoSama on 2016-09-17
//  Copyright (c) 2016 TaoSama. All rights reserved.
//
#pragma comment(linker, "/STACK:102400000,102400000")
#include <algorithm>
#include <cctype>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <map>
#include <queue>
#include <string>
#include <set>
#include <vector>

using namespace std;
#define pr(x) cout << #x << " = " << x << "  "
#define prln(x) cout << #x << " = " << x << endl
const int N = 1e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;

typedef long long LL;

LL quick(LL x, LL n) {
    LL ret = 1;
    for(; n; n >>= 1) {
        if(n & 1) ret = ret * x % MOD;
        x = x * x % MOD;
    }
    return ret;
}

LL C(LL n, LL m) {
    if(n < m) return 0;
    m = min(m, n - m);

    LL up = 1, dw = 1;
    for(int i = 0; i < m; ++i) {
        up = up * (n - i) % MOD;
        dw = dw * (i + 1) % MOD;
    }
    return up * quick(dw, MOD - 2) % MOD;
}

LL lucas(LL n, LL m) {
    if(m == 0) return 1;
    return C(n % MOD, m % MOD) * lucas(n / MOD, m / MOD) % MOD;
}

LL calc(LL n, LL m) {
    return lucas(n + m - 1, m - 1);
}

int n;
LL s, f[N];

int main() {
#ifdef LOCAL
    freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);
//  freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);
#endif
    ios_base::sync_with_stdio(0);

    while(cin >> n >> s) {
        for(int i = 0; i < n; ++i) cin >> f[i];

        LL ans = 0;
        for(int i = 0; i < 1 << n; ++i) {
            LL lft = s, cnt = 0;
            for(int j = 0; j < n; ++j) {
                if(i >> j & 1) {
                    lft -= f[j] + 1;
                    ++cnt;
                }
            }
            if(lft < 0) continue;

            if(cnt & 1) ans -= calc(lft, n);
            else ans += calc(lft, n);
            ans %= MOD;
        }
        ans = (ans + MOD) % MOD;
        cout << ans << endl;
    }

    return 0;
}